using System;
using System.Collections.Generic;
using System.Text;

namespace Toenda.Foundation.Drawing {
	/// <summary>
	/// Class ExifReader
	/// </summary>
	public class ExifReader : IDisposable {
		private System.Drawing.Bitmap _Image;
		private System.Text.Encoding _Encoding = System.Text.Encoding.UTF8;

		#region "Type declarations"

		/// <summary>
		/// Contains possible values of EXIF tag names (ID)
		/// </summary>
		/// <remarks>See GdiPlusImaging.h</remarks>
		public enum TagNames : int {
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifIFD = 34665,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsIFD = 34853,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			NewSubfileType = 254,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			SubfileType = 255,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ImageWidth = 256,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ImageHeight = 257,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			BitsPerSample = 258,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			Compression = 259,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PhotometricInterp = 262,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThreshHolding = 263,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			CellWidth = 264,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			CellHeight = 265,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			FillOrder = 266,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			DocumentName = 269,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ImageDescription = 270,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			EquipMake = 271,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			EquipModel = 272,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			StripOffsets = 273,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			Orientation = 274,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			SamplesPerPixel = 277,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			RowsPerStrip = 278,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			StripBytesCount = 279,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			MinSampleValue = 280,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			MaxSampleValue = 281,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			XResolution = 282,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			YResolution = 283,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PlanarConfig = 284,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PageName = 285,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			XPosition = 286,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			YPosition = 287,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			FreeOffset = 288,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			FreeByteCounts = 289,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GrayResponseUnit = 290,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GrayResponseCurve = 291,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			T4Option = 292,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			T6Option = 293,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ResolutionUnit = 296,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PageNumber = 297,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			TransferFuncition = 301,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			SoftwareUsed = 305,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			DateTime = 306,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			Artist = 315,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HostComputer = 316,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			Predictor = 317,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			WhitePoint = 318,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PrimaryChromaticities = 319,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ColorMap = 320,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HalftoneHints = 321,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			TileWidth = 322,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			TileLength = 323,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			TileOffset = 324,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			TileByteCounts = 325,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			InkSet = 332,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			InkNames = 333,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			NumberOfInks = 334,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			DotRange = 336,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			TargetPrinter = 337,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExtraSamples = 338,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			SampleFormat = 339,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			SMinSampleValue = 340,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			SMaxSampleValue = 341,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			TransferRange = 342,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGProc = 512,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGInterFormat = 513,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGInterLength = 514,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGRestartInterval = 515,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGLosslessPredictors = 517,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGPointTransforms = 518,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGQTables = 519,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGDCTables = 520,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGACTables = 521,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			YCbCrCoefficients = 529,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			YCbCrSubsampling = 530,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			YCbCrPositioning = 531,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			REFBlackWhite = 532,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ICCProfile = 34675,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			Gamma = 769,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ICCProfileDescriptor = 770,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			SRGBRenderingIntent = 771,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ImageTitle = 800,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			Copyright = 33432,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ResolutionXUnit = 20481,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ResolutionYUnit = 20482,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ResolutionXLengthUnit = 20483,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ResolutionYLengthUnit = 20484,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PrintFlags = 20485,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PrintFlagsVersion = 20486,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PrintFlagsCrop = 20487,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PrintFlagsBleedWidth = 20488,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PrintFlagsBleedWidthScale = 20489,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HalftoneLPI = 20490,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HalftoneLPIUnit = 20491,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HalftoneDegree = 20492,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HalftoneShape = 20493,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HalftoneMisc = 20494,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			HalftoneScreen = 20495,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			JPEGQuality = 20496,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GridSize = 20497,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailFormat = 20498,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailWidth = 20499,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailHeight = 20500,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailColorDepth = 20501,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailPlanes = 20502,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailRawBytes = 20503,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailSize = 20504,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailCompressedSize = 20505,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ColorTransferFunction = 20506,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailData = 20507,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailImageWidth = 20512,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailImageHeight = 1282,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailBitsPerSample = 20514,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailCompression = 20515,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailPhotometricInterp = 20516,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailImageDescription = 20517,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailEquipMake = 20518,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailEquipModel = 20519,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailStripOffsets = 20520,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailOrientation = 20521,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailSamplesPerPixel = 20522,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailRowsPerStrip = 20523,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailStripBytesCount = 20524,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailResolutionX = 20525,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailResolutionY = 20526,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailPlanarConfig = 20527,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailResolutionUnit = 20528,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailTransferFunction = 20529,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailSoftwareUsed = 20530,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailDateTime = 20531,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailArtist = 20532,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailWhitePoint = 20533,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailPrimaryChromaticities = 20534,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailYCbCrCoefficients = 20535,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailYCbCrSubsampling = 20536,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailYCbCrPositioning = 20537,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailRefBlackWhite = 20538,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ThumbnailCopyRight = 20539,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			LuminanceTable = 20624,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ChrominanceTable = 20625,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			FrameDelay = 20736,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			LoopCount = 20737,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PixelUnit = 20752,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PixelPerUnitX = 20753,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PixelPerUnitY = 20754,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			PaletteHistogram = 20755,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifExposureTime = 33434,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFNumber = 33437,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifExposureProg = 34850,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifSpectralSense = 34852,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifISOSpeed = 34855,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifOECF = 34856,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifVer = 36864,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifDTOrig = 36867,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifDTDigitized = 36868,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifCompConfig = 37121,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifCompBPP = 37122,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifShutterSpeed = 37377,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifAperture = 37378,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifBrightness = 37379,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifExposureBias = 37380,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifMaxAperture = 37381,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifSubjectDist = 37382,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifMeteringMode = 37383,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifLightSource = 37384,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFlash = 37385,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFocalLength = 37386,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifMakerNote = 37500,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifUserComment = 37510,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifDTSubsec = 37520,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifDTOrigSS = 37521,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifDTDigSS = 37522,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFPXVer = 40960,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifColorSpace = 40961,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifPixXDim = 40962,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifPixYDim = 40963,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifRelatedWav = 40964,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifInterop = 40965,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFlashEnergy = 41483,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifSpatialFR = 41484,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFocalXRes = 41486,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFocalYRes = 41487,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFocalResUnit = 41488,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifSubjectLoc = 41492,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifExposureIndex = 41493,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifSensingMethod = 41495,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifFileSource = 41728,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifSceneType = 41729,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			ExifCfaPattern = 41730,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsVer = 0,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsLatitudeRef = 1,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsLatitude = 2,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsLongitudeRef = 3,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsLongitude = 4,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsAltitudeRef = 5,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsAltitude = 6,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsGpsTime = 7,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsGpsSatellites = 8,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsGpsStatus = 9,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsGpsMeasureMode = 10,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsGpsDop = 11,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsSpeedRef = 12,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsSpeed = 13,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsTrackRef = 14,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsTrack = 15,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsImgDirRef = 16,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsImgDir = 17,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsMapDatum = 18,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestLatRef = 19,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestLat = 20,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestLongRef = 21,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestLong = 22,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestBearRef = 23,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestBear = 24,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestDistRef = 25,
			/// <summary>
			/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
			/// </summary>
			GpsDestDist = 26
		}

		/// <summary>
		/// Real position of 0th row and column of picture
		/// </summary>
		/// <remarks></remarks>
		public enum Orientations {
			/// <summary>
			/// 
			/// </summary>
			TopLeft = 1,
			/// <summary>
			/// 
			/// </summary>
			TopRight = 2,
			/// <summary>
			/// 
			/// </summary>
			BottomRight = 3,
			/// <summary>
			/// 
			/// </summary>
			BottomLeft = 4,
			/// <summary>
			/// 
			/// </summary>
			LeftTop = 5,
			/// <summary>
			/// 
			/// </summary>
			RightTop = 6,
			/// <summary>
			/// 
			/// </summary>
			RightBottom = 7,
			/// <summary>
			/// 
			/// </summary>
			LftBottom = 8
		}

		/// <summary>
		/// Exposure programs
		/// </summary>
		/// <remarks></remarks>
		public enum ExposurePrograms {
			/// <summary>
			/// 
			/// </summary>
			Manual = 1,
			/// <summary>
			/// 
			/// </summary>
			Normal = 2,
			/// <summary>
			/// 
			/// </summary>
			AperturePriority = 3,
			/// <summary>
			/// 
			/// </summary>
			ShutterPriority = 4,
			/// <summary>
			/// 
			/// </summary>
			Creative = 5,
			/// <summary>
			/// 
			/// </summary>
			Action = 6,
			/// <summary>
			/// 
			/// </summary>
			Portrait = 7,
			/// <summary>
			/// 
			/// </summary>
			Landscape = 8
		}

		/// <summary>
		/// Exposure metering modes
		/// </summary>
		/// <remarks></remarks>
		public enum ExposureMeteringModes {
			/// <summary>
			/// 
			/// </summary>
			Unknown = 0,
			/// <summary>
			/// 
			/// </summary>
			Average = 1,
			/// <summary>
			/// 
			/// </summary>
			CenterWeightedAverage = 2,
			/// <summary>
			/// 
			/// </summary>
			Spot = 3,
			/// <summary>
			/// 
			/// </summary>
			MultiSpot = 4,
			/// <summary>
			/// 
			/// </summary>
			MultiSegment = 5,
			/// <summary>
			/// 
			/// </summary>
			Partial = 6,
			/// <summary>
			/// 
			/// </summary>
			Other = 255
		}

		/// <summary>
		/// Flash activity modes
		/// </summary>
		/// <remarks></remarks>
		public enum FlashModes {
			/// <summary>
			/// 
			/// </summary>
			NotFired = 0,
			/// <summary>
			/// 
			/// </summary>
			Fired = 1,
			/// <summary>
			/// 
			/// </summary>
			FiredButNoStrobeReturned = 5,
			/// <summary>
			/// 
			/// </summary>
			FiredAndStrobeReturned = 7
		}

		/// <summary>
		/// Possible light sources (white balance)
		/// </summary>
		/// <remarks></remarks>
		public enum LightSources {
			/// <summary>
			/// 
			/// </summary>
			Unknown = 0,
			/// <summary>
			/// 
			/// </summary>
			Daylight = 1,
			/// <summary>
			/// 
			/// </summary>
			Fluorescent = 2,
			/// <summary>
			/// 
			/// </summary>
			Tungsten = 3,
			/// <summary>
			/// 
			/// </summary>
			Flash = 10,
			/// <summary>
			/// 
			/// </summary>
			StandardLightA = 17,
			/// <summary>
			/// 
			/// </summary>
			StandardLightB = 18,
			/// <summary>
			/// 
			/// </summary>
			StandardLightC = 19,
			/// <summary>
			/// 
			/// </summary>
			D55 = 20,
			/// <summary>
			/// 
			/// </summary>
			D65 = 21,
			/// <summary>
			/// 
			/// </summary>
			D75 = 22,
			/// <summary>
			/// 
			/// </summary>
			Other = 255
		}

		/// <summary>
		/// EXIF data types
		/// </summary>
		/// <remarks></remarks>
		public enum ExifDataTypes : short {
			/// <summary>
			/// 
			/// </summary>
			UnsignedByte = 1,
			/// <summary>
			/// 
			/// </summary>
			AsciiString = 2,
			/// <summary>
			/// 
			/// </summary>
			UnsignedShort = 3,
			/// <summary>
			/// 
			/// </summary>
			UnsignedLong = 4,
			/// <summary>
			/// 
			/// </summary>
			UnsignedRational = 5,
			/// <summary>
			/// 
			/// </summary>
			SignedByte = 6,
			/// <summary>
			/// 
			/// </summary>
			Undefined = 7,
			/// <summary>
			/// 
			/// </summary>
			SignedShort = 8,
			/// <summary>
			/// 
			/// </summary>
			SignedLong = 9,
			/// <summary>
			/// 
			/// </summary>
			SignedRational = 10,
			/// <summary>
			/// 
			/// </summary>
			SingleFloat = 11,
			/// <summary>
			/// 
			/// </summary>
			DoubleFloat = 12
		}

		/// <summary>
		/// Represents rational which is type of some Exif properties
		/// </summary>
		/// <remarks></remarks>
		public struct Rational {
			/// <summary>
			/// Numerator
			/// </summary>
			public Int32 Numerator;
			/// <summary>
			/// Denominator
			/// </summary>
			public Int32 Denominator;

			/// <summary>
			/// Converts rational to string representation
			/// </summary>
			/// <param name="Delimiter">Optional, default "/". String to be used as delimiter of components.</param>
			/// <returns>String representation of the rational.</returns>
			/// <remarks></remarks>
			public string ToString(string Delimiter) {
				return Numerator + Delimiter + Denominator;
			}

			/// <summary>
			/// Converts rational to double precision real number
			/// </summary>
			/// <returns>The rational as double precision real number.</returns>
			/// <remarks></remarks>
			public double ToDouble() {
				return Numerator / Denominator;
			}
		}

		#endregion

		/// <summary>
		/// Initializes new instance of this class.
		/// </summary>
		/// <param name="Bitmap">Bitmap to read exif information from</param>
		/// <remarks></remarks>
		public ExifReader(ref System.Drawing.Bitmap Bitmap) {
			if(Bitmap == null)
				throw new ArgumentNullException("Bitmap");

			this._Image = Bitmap;
		}

		/// <summary>
		/// Initializes new instance of this class.
		/// </summary>
		/// <param name="FileName">Name of file to be loaded</param>
		/// <remarks></remarks>
		public ExifReader(string FileName) {
			this._Image = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromFile(FileName);
		}

		/// <summary>
		/// Get or set encoding used for string metadata
		/// </summary>
		/// <value>Encoding used for string metadata</value>
		/// <remarks>Default encoding is UTF-8</remarks>
		public System.Text.Encoding Encoding {
			get { return this._Encoding; }
			set {
				if(value == null)
					throw new ArgumentNullException();

				this._Encoding = Encoding;
			}
		}

		/// <summary>
		/// Returns copy of bitmap this instance is working on
		/// </summary>
		/// <returns></returns>
		/// <remarks></remarks>
		public System.Drawing.Bitmap GetBitmap() {
			return (System.Drawing.Bitmap)this._Image.Clone();
		}

		/// <summary>
		/// Returns all available data in formatted string form
		/// </summary>
		/// <returns></returns>
		/// <remarks></remarks>
		public override string ToString() {
			System.Text.StringBuilder SB = new System.Text.StringBuilder();

			SB.Append("Image:");
			SB.Append("\n\tDimensions:        " + this.Width + " x " + this.Height + " px");
			SB.Append("\n\tResolution:        " + this.ResolutionX + " x " + this.ResolutionY + " dpi");
			SB.Append("\n\tOrientation:       " + Enum.GetName(typeof(Orientations), this.Orientation));
			SB.Append("\n\tTitle:             " + this.Title);
			SB.Append("\n\tDescription:       " + this.Description);
			SB.Append("\n\tCopyright:         " + this.Copyright);
			SB.Append("\nEquipment:");
			SB.Append("\n\tMaker:             " + this.EquipmentMaker);
			SB.Append("\n\tModel:             " + this.EquipmentModel);
			SB.Append("\n\tSoftware:          " + this.Software);
			SB.Append("\nDate and time:");
			SB.Append("\n\tGeneral:           " + this.DateTimeLastModified.ToString());
			SB.Append("\n\tOriginal:          " + this.DateTimeOriginal.ToString());
			SB.Append("\n\tDigitized:         " + this.DateTimeDigitized.ToString());
			SB.Append("\nShooting conditions:");
			SB.Append("\n\tExposure time:     " + this.ExposureTime.ToString("N4") + " s");
			SB.Append("\n\tExposure program:  " + Enum.GetName(typeof(ExposurePrograms), this.ExposureProgram));
			SB.Append("\n\tExposure mode:     " + Enum.GetName(typeof(ExposureMeteringModes), this.ExposureMeteringMode));
			SB.Append("\n\tAperture:          F" + this.Aperture.ToString("N2"));
			SB.Append("\n\tISO sensitivity:   " + this.ISO);
			SB.Append("\n\tSubject distance:  " + this.SubjectDistance.ToString("N2") + " m");
			SB.Append("\n\tFocal length:      " + this.FocalLength);
			SB.Append("\n\tFlash:             " + Enum.GetName(typeof(FlashModes), this.FlashMode));
			SB.Append("\n\tLight source (WB): " + Enum.GetName(typeof(LightSources), this.LightSource));

			return SB.ToString();
		}

		#region " Properties "

		/// <summary>
		/// Brand of equipment (EXIF EquipMake)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string EquipmentMaker {
			get { return this.GetPropertyString((int)TagNames.EquipMake, ""); }
		}

		/// <summary>
		/// Model of equipment (EXIF EquipModel)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string EquipmentModel {
			get { return this.GetPropertyString((int)TagNames.EquipModel, ""); }
		}

		/// <summary>
		/// Software used for processing (EXIF Software)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string Software {
			get { return this.GetPropertyString((int)TagNames.SoftwareUsed, ""); }
		}

		/// <summary>
		/// Orientation of image (position of row 0, column 0) (EXIF Orientation)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public Orientations Orientation {
			get {
				Int32 X = this.GetPropertyInt16((int)TagNames.Orientation, 0);

				if(!Enum.IsDefined(typeof(Orientations), X)) {
					return Orientations.TopLeft;
				}
				else {
					return (Orientations)Enum.Parse(typeof(Orientations), Enum.GetName(typeof(Orientations), X));
				}
			}
		}

		/// <summary>
		/// Time when image was last modified (EXIF DateTime).
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public DateTime DateTimeLastModified {
			get {
				try {
					return DateTime.ParseExact(this.GetPropertyString((int)TagNames.DateTime, ""), "yyyy\\:MM\\:dd HH\\:mm\\:ss", null);
				}
				catch(Exception ex) {
					string err1 = ex.Message;
					return DateTime.MinValue;
				}
			}
			set {
				try {
					this.SetPropertyString((int)TagNames.DateTime, value.ToString("yyyy\\:MM\\:dd HH\\:mm\\:ss"));
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// Time when image was taken (EXIF DateTimeOriginal).
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public DateTime DateTimeOriginal {
			get {
				try {
					return DateTime.ParseExact(this.GetPropertyString((int)TagNames.ExifDTOrig, ""), "yyyy\\:MM\\:dd HH\\:mm\\:ss", null);
				}
				catch(Exception ex) {
					string err1 = ex.Message;
					return DateTime.MinValue;
				}
			}
			set {
				try {
					this.SetPropertyString((int)TagNames.ExifDTOrig, value.ToString("yyyy\\:MM\\:dd HH\\:mm\\:ss"));
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// Time when image was digitized (EXIF DateTimeDigitized).
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public DateTime DateTimeDigitized {
			get {
				try {
					return DateTime.ParseExact(this.GetPropertyString((int)TagNames.ExifDTDigitized, ""), "yyyy\\:MM\\:dd HH\\:mm\\:ss", null);
				}
				catch(Exception ex) {
					string err1 = ex.Message;
					return DateTime.MinValue;
				}
			}
			set {
				try {
					this.SetPropertyString((int)TagNames.ExifDTDigitized, value.ToString("yyyy\\:MM\\:dd HH\\:mm\\:ss"));
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// Image width
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public Int32 Width {
			get { return this._Image.Width; }
		}

		/// <summary>
		/// Image height
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public Int32 Height {
			get { return this._Image.Height; }
		}

		/// <summary>
		/// X resolution in dpi (EXIF XResolution/ResolutionUnit)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public double ResolutionX {
			get {
				double R = this.GetPropertyRational((int)TagNames.XResolution).ToDouble();

				if(this.GetPropertyInt16((int)TagNames.ResolutionUnit, 0) == 3) {
					return R * 2.54;
				}
				else {
					return R;
				}
			}
		}

		/// <summary>
		/// Y resolution in dpi (EXIF YResolution/ResolutionUnit)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public double ResolutionY {
			get {
				double R = this.GetPropertyRational((int)TagNames.YResolution).ToDouble();

				if(this.GetPropertyInt16((int)TagNames.ResolutionUnit, 0) == 3) {
					return R * 2.54;
				}
				else {
					return R;
				}
			}
		}

		/// <summary>
		/// Image title (EXIF ImageTitle)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string Title {
			get { return this.GetPropertyString((int)TagNames.ImageTitle, ""); }
			set {
				try {
					this.SetPropertyString((int)TagNames.ImageTitle, value);
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// User comment (EXIF UserComment)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string UserComment {
			get { return this.GetPropertyString((int)TagNames.ExifUserComment, ""); }
			set {
				try {
					this.SetPropertyString((int)TagNames.ExifUserComment, value);
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// Artist name (EXIF Artist)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string Artist {
			get { return this.GetPropertyString((int)TagNames.Artist, ""); }
			set {
				try {
					this.SetPropertyString((int)TagNames.Artist, value);
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// Image description (EXIF ImageDescription)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string Description {
			get { return this.GetPropertyString((int)TagNames.ImageDescription, ""); }
			set {
				try {
					this.SetPropertyString((int)TagNames.ImageDescription, value);
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// Image copyright (EXIF Copyright)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public string Copyright {
			get { return this.GetPropertyString((int)TagNames.Copyright, ""); }
			set {
				try {
					this.SetPropertyString((int)TagNames.Copyright, value.ToString());
				}
				catch(Exception ex) {
					string err2 = ex.Message;
				}
			}
		}

		/// <summary>
		/// Exposure time in seconds (EXIF ExifExposureTime/ExifShutterSpeed)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public double ExposureTime {
			get {
				if(this.IsPropertyDefined((int)TagNames.ExifExposureTime)) {
					return this.GetPropertyRational((int)TagNames.ExifExposureTime).ToDouble();
				}
				else if(this.IsPropertyDefined((int)TagNames.ExifShutterSpeed)) {
					return 1 / (System.Math.Pow(2, this.GetPropertyRational((int)TagNames.ExifShutterSpeed).ToDouble()));
				}
				else {
					return 0;
				}
			}
		}

		/// <summary>
		/// Aperture value as F number (EXIF ExifFNumber/ExifApertureValue)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public double Aperture {
			get {
				if(this.IsPropertyDefined((int)TagNames.ExifFNumber)) {
					return this.GetPropertyRational((int)TagNames.ExifFNumber).ToDouble();
				}
				else if(this.IsPropertyDefined((int)TagNames.ExifAperture)) {
					return System.Math.Pow(System.Math.Sqrt(2), this.GetPropertyRational((int)TagNames.ExifAperture).ToDouble());
				}
				else {
					return 0;
				}
			}
		}

		/// <summary>
		/// Exposure program used (EXIF ExifExposureProg)
		/// </summary>
		/// <value></value>
		/// <remarks>If not specified, returns Normal (2)</remarks>
		public ExposurePrograms ExposureProgram {
			get {
				Int32 X = this.GetPropertyInt16((int)TagNames.ExifExposureProg, 0);

				if(Enum.IsDefined(typeof(ExposurePrograms), X)) {
					return (ExposurePrograms)Enum.Parse(typeof(ExposurePrograms), Enum.GetName(typeof(ExposurePrograms), X));
				}
				else {
					return ExposurePrograms.Normal;
				}
			}
		}

		/// <summary>
		/// ISO sensitivity
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public Int16 ISO {
			get { return this.GetPropertyInt16((int)TagNames.ExifISOSpeed, 0); }
		}

		/// <summary>
		/// Subject distance in meters (EXIF SubjectDistance)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public double SubjectDistance {
			get { return this.GetPropertyRational((int)TagNames.ExifSubjectDist).ToDouble(); }
		}

		/// <summary>
		/// Exposure method metering mode used (EXIF MeteringMode)
		/// </summary>
		/// <value></value>
		/// <remarks>If not specified, returns Unknown (0)</remarks>
		public ExposureMeteringModes ExposureMeteringMode {
			get {
				Int32 X = this.GetPropertyInt16((int)TagNames.ExifMeteringMode, 0);

				if(Enum.IsDefined(typeof(ExposureMeteringModes), X)) {
					return (ExposureMeteringModes)Enum.Parse(typeof(ExposureMeteringModes), Enum.GetName(typeof(ExposureMeteringModes), X));
				}
				else {
					return ExposureMeteringModes.Unknown;
				}
			}
		}

		/// <summary>
		/// Focal length of lenses in mm (EXIF FocalLength)
		/// </summary>
		/// <value></value>
		/// <remarks></remarks>
		public double FocalLength {
			get { return this.GetPropertyRational((int)TagNames.ExifFocalLength).ToDouble(); }
		}

		/// <summary>
		/// Flash mode (EXIF Flash)
		/// </summary>
		/// <value></value>
		/// <remarks>If not present, value NotFired (0) is returned</remarks>
		public FlashModes FlashMode {
			get {
				Int32 X = this.GetPropertyInt16((int)TagNames.ExifFlash, 0);

				if(Enum.IsDefined(typeof(FlashModes), X)) {
					return (FlashModes)Enum.Parse(typeof(FlashModes), Enum.GetName(typeof(FlashModes), X));
				}
				else {
					return FlashModes.NotFired;
				}
			}
		}

		/// <summary>
		/// Light source / white balance (EXIF LightSource)
		/// </summary>
		/// <value></value>
		/// <remarks>If not specified, returns Unknown (0).</remarks>
		public LightSources LightSource {
			get {
				Int32 X = this.GetPropertyInt16((int)TagNames.ExifLightSource, 0);

				if(Enum.IsDefined(typeof(LightSources), X)) {
					return (LightSources)Enum.Parse(typeof(LightSources), Enum.GetName(typeof(LightSources), X));
				}
				else {
					return LightSources.Unknown;
				}
			}
		}

		#endregion

		#region " Support methods for working with EXIF properties "

		/// <summary>
		/// Checks if current image has specified certain property
		/// </summary>
		/// <param name="PID">The PID.</param>
		/// <returns>
		/// True if image has specified property, False otherwise.
		/// </returns>
		/// <remarks></remarks>
		public bool IsPropertyDefined(Int32 PID) {
			return Convert.ToBoolean(Array.IndexOf(this._Image.PropertyIdList, PID) > -1);
		}

		/// <summary>
		/// Gets specified Int32 property
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="DefaultValue">Optional, default 0. Default value returned if property is not present.</param>
		/// <returns></returns>
		/// <remarks>Value of property or DefaultValue if property is not present.</remarks>
		/// <remarks></remarks>
		public Int32 GetPropertyInt32(Int32 PID, Int32 DefaultValue) {
			if(this.IsPropertyDefined(PID)) {
				return GetInt32(this._Image.GetPropertyItem(PID).Value);
			}
			else {
				return DefaultValue;
			}
		}

		/// <summary>
		/// Gets specified Int16 property
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="DefaultValue">Optional, default 0. Default value returned if property is not present.</param>
		/// <remarks>Value of property or DefaultValue if property is not present.</remarks>
		/// <remarks></remarks>
		public Int16 GetPropertyInt16(Int32 PID, Int16 DefaultValue) {
			if(this.IsPropertyDefined(PID)) {
				return GetInt16(this._Image.GetPropertyItem(PID).Value);
			}
			else {
				return DefaultValue;
			}
		}

		/// <summary>
		/// Gets specified string property
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="DefaultValue">Optional, default String.Empty. Default value returned if property is not present.</param>
		/// <returns></returns>
		/// <remarks>Value of property or DefaultValue if property is not present.</remarks>
		public string GetPropertyString(Int32 PID, string DefaultValue) {
			if(this.IsPropertyDefined(PID)) {
				return GetString(this._Image.GetPropertyItem(PID).Value);
			}
			else {
				return DefaultValue;
			}
		}

		/// <summary>
		/// Gets specified property in raw form
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="DefaultValue">Optional, default Nothing. Default value returned if property is not present.</param>
		/// <returns></returns>
		/// <remarks>Is recommended to use typed methods (like <see cref="GetPropertyString" /> etc.) instead, when possible.</remarks>
		public byte[] GetProperty(Int32 PID, byte[] DefaultValue) {
			if(this.IsPropertyDefined(PID)) {
				return this._Image.GetPropertyItem(PID).Value;
			}
			else {
				return DefaultValue;
			}
		}

		/// <summary>
		/// Gets specified rational property
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <returns></returns>
		/// <remarks>Value of property or 0/1 if not present.</remarks>
		public Rational GetPropertyRational(Int32 PID) {
			if(this.IsPropertyDefined(PID)) {
				return GetRational(this._Image.GetPropertyItem(PID).Value);
			}
			else {
				Rational R;
				R.Numerator = 0;
				R.Denominator = 1;
				return R;
			}
		}

		/// <summary>
		/// Sets specified string property
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="Value">Value to be set</param>
		/// <remarks></remarks>
		public void SetPropertyString(Int32 PID, string Value) {
			byte[] Data = this._Encoding.GetBytes(Value + "\0");
			SetProperty(PID, Data, ExifDataTypes.AsciiString);
		}

		/// <summary>
		/// Sets specified Int16 property
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="Value">Value to be set</param>
		/// <remarks></remarks>
		public void SetPropertyInt16(Int32 PID, Int16 Value) {
			byte[] Data = new byte[2];
			Data[0] = Convert.ToByte(Value & 255);
			Data[1] = Convert.ToByte((Value & 65280) >> 8);
			SetProperty(PID, Data, ExifDataTypes.SignedShort);
		}

		/// <summary>
		/// Sets specified Int32 property
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="Value">Value to be set</param>
		/// <remarks></remarks>
		public void SetPropertyInt32(Int32 PID, Int32 Value) {
			byte[] Data = new byte[4];
			for(Int32 I = 0; I <= 3; I++) {
				Data[I] = Convert.ToByte(Value & 255);
				Value >>= 8;
			}
			SetProperty(PID, Data, ExifDataTypes.SignedLong);
		}

		/// <summary>
		/// Sets specified propery in raw form
		/// </summary>
		/// <param name="PID">Property ID</param>
		/// <param name="Data">Raw data</param>
		/// <param name="Type">EXIF data type</param>
		/// <remarks>Is recommended to use typed methods (like <see cref="SetPropertyString" /> etc.) instead, when possible.</remarks>
		public void SetProperty(Int32 PID, byte[] Data, ExifDataTypes Type) {
			System.Drawing.Imaging.PropertyItem P = this._Image.PropertyItems[0];
			P.Id = PID;
			P.Value = Data;
			P.Type = (short)Type;
			P.Len = Data.Length;
			this._Image.SetPropertyItem(P);
		}

		/// <summary>
		/// Reads Int32 from EXIF bytearray.
		/// </summary>
		/// <param name="B">EXIF bytearray to process</param>
		/// <returns></returns>
		/// <remarks></remarks>
		private Int32 GetInt32(byte[] B) {
			if(B.Length < 4) throw new ArgumentException("Data too short (4 bytes expected)", "B");
			return B[3] << 24 | B[2] << 16 | B[1] << 8 | B[0];
		}

		/// <summary>
		/// Reads Int16 from EXIF bytearray.
		/// </summary>
		/// <param name="B">EXIF bytearray to process</param>
		/// <returns></returns>
		/// <remarks></remarks>
		private Int16 GetInt16(byte[] B) {
			if(B.Length < 2) throw new ArgumentException("Data too short (2 bytes expected)", "B");
			return Convert.ToInt16(B[1] << 8 | B[0]);
		}

		/// <summary>
		/// Reads string from EXIF bytearray.
		/// </summary>
		/// <param name="B">EXIF bytearray to process</param>
		/// <returns></returns>
		/// <remarks></remarks>
		private string GetString(byte[] B) {
			string R = this._Encoding.GetString(B);
			if(R.EndsWith("\0")) R = R.Substring(0, R.Length - 1);
			return R;
		}

		/// <summary>
		/// Reads rational from EXIF bytearray.
		/// </summary>
		/// <param name="B">EXIF bytearray to process</param>
		/// <returns></returns>
		/// <remarks></remarks>
		private Rational GetRational(byte[] B) {
			Rational R = new Rational();
			byte[] N = new byte[4];
			byte[] D = new byte[4];
			Array.Copy(B, 0, N, 0, 4);
			Array.Copy(B, 4, D, 0, 4);
			R.Denominator = this.GetInt32(D);
			R.Numerator = this.GetInt32(N);
			return R;
		}

		#endregion

		#region " IDisposable implementation "

		/// <summary>
		/// Disposes unmanaged resources of this class
		/// </summary>
		/// <remarks></remarks>
		void System.IDisposable.Dispose() {
			this._Image.Dispose();
		}

		#endregion
	}
}
